<?php
use GatewayClient\Gateway;

error_reporting(E_ALL);
header('Content-Type: text/html;charset=utf-8');
mb_internal_encoding('UTF-8');
set_error_handler(array('core', 'error_handler'));
session_start();
ob_start(array('core', 'ob_output'));

//设置时区
date_default_timezone_set("PRC");
if(!defined('PATH_SYSTEM') || !defined('PATH_MODEL') || !defined('PATH_CONTROLLER')) die('Access Denied!');
class core {
    public static $theme = 'default';
    //初始化
    public static function init() {
        Gateway::$registerAddress = Gateway_registerAddress.':'.Gateway_registerAddress_PORT;
        /* 对用户传入的变量进行转义操作。*/
        /*
        if (!get_magic_quotes_gpc())
        {
            if(!empty($_GET))
            {
                $_GET  = self::addslashes_deep($_GET,true);
            }
            if(!empty($_POST)){
                $_POST = self::addslashes_deep($_POST,true);
            }
            $_COOKIE   = self::addslashes_deep($_COOKIE,true);
            $_REQUEST  = self::addslashes_deep($_REQUEST,true);
        }
        */
        $browerinfo = self::BrowerInfo();
        //加载通用M
        require(PATH_ROOT.'/core/mod.php');
        if (count($browerinfo['path']) < 3) self::__403();
        $model_name = $browerinfo['path'][1];
        $controller_name = $browerinfo['path'][2];
        //载入M和C
        if (!preg_match('/^[a-z0-9_\-]+$/', $model_name) || !preg_match('/^[a-z0-9_\-]+$/', $controller_name)) self::__403();
        $model_file = PATH_MODEL.'/'.$model_name.'.model.php';
        if (!is_file($model_file)) self::__403();
        require($model_file);

        $controller_file = PATH_CONTROLLER.'/'.$model_name.'.controller.php';
        if (!is_file($controller_file)) self::__403($controller_file);
        require($controller_file);
        $controller_classname = 'controller_'.$model_name;
        $controllerclass = new $controller_classname;
        $controllers = get_class_methods($controllerclass);

        if (!in_array($controller_name, $controllers)) self::__403();
        call_user_func_array(array($controllerclass, $controller_name), array());
    }
    /*
    * 取出地址栏中的数据分析M,V,C
    */
    public static function BrowerInfo(){
        $uri = array_key_exists('REQUEST_URI', $_SERVER) ? $_SERVER['REQUEST_URI'] : '/';
        $uri_info = parse_url($uri);
        $client_type = self::convertUrlQuery((array_key_exists('query',$uri_info) ? $uri_info['query'] : ''));
        $client_type = is_array($client_type) && array_key_exists('client_type',$client_type) ? ($client_type['client_type']) : (self::isMobile()?'mobile':'web');
        if (!is_array($uri_info) || !array_key_exists('path', $uri_info)) self::__403();
        $path = explode('/', $uri_info['path'] === '/' ? '/home/'.$client_type : $uri_info['path']);
        return array(
            'client_type' => $client_type,
            'path' => $path,
        );
    }
    /**
     * Returns the url query as associative array
     *
     * @param    string    query
     * @return    array    params
     */
    public static function convertUrlQuery($query)
    {
        //var_dump($query);
        //$query = (is_array($query) && count($query)) ? $query : '';
        $queryParts = explode('&', $query);
        $params = array();
        if(count($queryParts)>0){
            foreach ($queryParts as $param)
            {
                $item = explode('=', $param);
                if(is_array($item) && !empty($item[0])){
                    // 如果是?385734这种样式的链接，键名处理成键值
                    $params[$item[0]] = isset($item[1]) ? $item[1] : $item[0];
                }
            }
        }
        return $params;
    }
    public static function getUrlQuery($array_query)
    {
        $tmp = array();
        foreach($array_query as $k=>$param)
        {
            $tmp[] = $k.'='.$param;
        }
        $params = implode('&',$tmp);
        return $params;
    }
    /*
     * 检测手机还是PC
     */
    public static function isMobile()
    {
        // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
        if (isset ($_SERVER['HTTP_X_WAP_PROFILE']))
        {
            return true;
        }
        // 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
        if (isset ($_SERVER['HTTP_VIA']))
        {
            // 找不到为flase,否则为true
            return stristr($_SERVER['HTTP_VIA'], "wap") ? true : false;
        }
        // 脑残法，判断手机发送的客户端标志,兼容性有待提高
        if (isset ($_SERVER['HTTP_USER_AGENT']))
        {
            $clientkeywords = array ('nokia',
                'sony',
                'ericsson',
                'mot',
                'samsung',
                'htc',
                'sgh',
                'lg',
                'sharp',
                'sie-',
                'philips',
                'panasonic',
                'alcatel',
                'lenovo',
                'iphone',
                'ipod',
                'blackberry',
                'meizu',
                'android',
                'netfront',
                'symbian',
                'ucweb',
                'windowsce',
                'palm',
                'operamini',
                'operamobi',
                'openwave',
                'nexusone',
                'cldc',
                'midp',
                'wap',
                'mobile'
            );
            // 从HTTP_USER_AGENT中查找手机浏览器的关键字
            if (preg_match("/(" . implode('|', $clientkeywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT'])))
            {
                return true;
            }
        }
        // 协议法，因为有可能不准确，放到最后判断
        if (isset ($_SERVER['HTTP_ACCEPT']))
        {
            // 如果只支持wml并且不支持html那一定是移动设备
            // 如果支持wml和html但是wml在html之前则是移动设备
            if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html'))))
            {
                return true;
            }
        }
        return false;
    }
    public static function ob_output($html) {
        // 一些用户喜欢使用windows笔记本编辑文件，因此在输出时需要检查是否包含BOM头
        if (ord(substr($html, 0, 1)) === 239 && ord(substr($html, 1, 2)) === 187 && ord(substr($html, 2, 1)) === 191) $html = substr($html, 3);
        // gzip输出
        if(
            !headers_sent() && // 如果页面头部信息还没有输出
            extension_loaded("zlib") && // 而且zlib扩展已经加载到PHP中
            array_key_exists('HTTP_ACCEPT_ENCODING', $_SERVER) &&
            stripos($_SERVER["HTTP_ACCEPT_ENCODING"], "gzip") !== false // 而且浏览器说它可以接受GZIP的页面
        ) {
            $html = gzencode($html, 3);
            header('Content-Encoding: gzip');
            header('Vary: Accept-Encoding');
        }
        header('Content-Length: '.strlen($html));
        return $html;
    }

    /**
     * @name 类库调用
     * @param string name 类库名称
     * @return object
     */
    public static function plus($name) {
        static $libs = array();
        if (!array_key_exists($name, $libs)) {
            require(PATH_ROOT.'/plus/'.$name.'.plus.php');
            $classname = 'plus_'.$name;
            $libs[$name] = new $classname;
        }
        return $libs[$name];
    }

    /*
    * 非法请求简写模式
     * @param string $string
     */
    public static function __403($string='') {
        self::error('非法请求-'.$string);
    }

    /**
     * @name 错误输出
     * @param string message 错误信息
     */
    public static function error($message='') {
        //print_r(debug_backtrace());
        header('X-Error-Message: '.rawurlencode($message));
        $msg = $message;
        require(PATH_ROOT.'/views/common/error.view.php');
        exit;
    }
    /**
     * @name 错误输出
     * @param string message 错误信息
     */
    public static function success($message='',$url='',$timelen = 5) {
        //print_r(debug_backtrace());
        header('X-Error-Message: '.rawurlencode($message));
        $msg = $message;
        $time = $timelen;
        require(core::$theme.'/common/success.view.php');
        exit;
    }
    /**
     * @name 日志记录
     * @param array data 日志数据
     */
    public static function logger($data) {
        if(ISDEBUG){
            $text = '';
            $data['TIME'] = date('Y-m-d H:i:s');
            $data['URI'] = $_SERVER['REQUEST_URI'];
            foreach ($data as $k => $v) $text .= '['.$k.']: '.$v."<br />";
            $text .= "<br />";
            echo $text;
            exit;
        }else{
            $text = '';
            $data['TIME'] = date('Y-m-d H:i:s');
            $data['URI'] = $_SERVER['REQUEST_URI'];
            foreach ($data as $k => $v) $text .= '['.$k.']: '.$v."\r\n";
            $text .= "\r\n";
            file_put_contents(PATH_ROOT.'/data/log/'.date('Y.m.d').'.txt', $text, FILE_APPEND);
        }
    }

    /**
     * @name 错误捕获
     * @param int type 错误类型
     * @param string message 错误信息
     * @param string file 错误文件
     * @param string line 错误行号
     */
    public static function error_handler($type, $message, $file, $line) {
        $data = array(
            'MSG'  => $message,
            'FILE' => $file,
            'LINE' => $line,
        );
        self::logger($data);
        if ($type !== E_WARNING && $type !== E_NOTICE && $type !== E_STRICT) self::error($message);
    }
    //特殊字符进行转义防注入
    public static function addslashes_deep($value,$htmlspecialchars=false)
    {
        if (empty($value))
        {
            return $value;
        }
        else
        {
            if(is_array($value))
            {
                foreach($value as $key => $v)
                {
                    unset($value[$key]);

                    if($htmlspecialchars==true)
                    {
                        $key=addslashes(htmlspecialchars($key));
                    }
                    else{
                        $key=addslashes($key);
                    }

                    if(is_array($v))
                    {
                        $value[$key] = self::addslashes_deep($v);
                    }
                    else{
                        if($htmlspecialchars==true)
                        {
                            $value[$key]=addslashes(htmlspecialchars($v));
                        }
                        else{
                            $value[$key]=addslashes($v);
                        }
                    }
                    $value[$key]=self::RemoveXSS($v);
                }
            }
            else{
                if($htmlspecialchars==true)
                {
                    $value=addslashes(htmlspecialchars($value));
                }
                else{
                    $value=addslashes($value);
                }
                $value = self::RemoveXSS($value);
            }
            //var_dump($value);
            return $value;
        }
    }

    //RemoveXss函数主要用于跨站脚本的过滤
    //Remove the exploer'bug XSS
    public static function RemoveXSS($val) {
        // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
        // this prevents some character re-spacing such as <java\0script>
        // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
        //$val = preg_replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '', $val); //这里会逗号也去除
        //$val = preg_replace('/([\x00-\x08|\x0b-\x0c|\x0e-\x19])/', '', $val);  // ,改成|号后就不会去除 , 了
        // straight replacements, the user should never need these since they're normal characters
        // this prevents like <IMG SRC=@avascript:alert('XSS')>
        $search = 'abcdefghijklmnopqrstuvwxyz';
        $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $search .= '1234567890!@#$%^&*()';
        $search .= '~`";:?+/={}[]-_|\'\\';
        for ($i = 0; $i < strlen($search); $i++) {
            // ;? matches the ;, which is optional
            // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
            // @ @ search for the hex values
            $val = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ;
            // @ @ 0{0,7} matches '0' zero to seven times
            $val = preg_replace('/(&#0{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ;
        }
        // now the only remaining whitespace attacks are \t, \n, and \r
        $ra1 = array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'style', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base');
        $ra2 = array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');
        $ra = array_merge($ra1, $ra2);
        $found = true; // keep replacing as long as the previous round replaced something
        while ($found == true) {
            $val_before = $val;
            for ($i = 0; $i < sizeof($ra); $i++) {
                $pattern = '/';
                for ($j = 0; $j < strlen($ra[$i]); $j++) {
                    if ($j > 0) {
                        $pattern .= '(';
                        $pattern .= '(&#[xX]0{0,8}([9ab]);)';
                        $pattern .= '|';
                        $pattern .= '|(&#0{0,8}([9|10|13]);)';
                        $pattern .= ')*';
                    }
                    $pattern .= $ra[$i][$j];
                }
                $pattern .= '/i';
                $replacement = substr($ra[$i], 0, 2).'<x>'.substr($ra[$i], 2); // add in <> to nerf the tag
                $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
                if ($val_before == $val) {
                    // no replacements were made, so exit the loop
                    $found = false;
                }
            }
        }
        return $val;
    }

}